<?php
/**
 * Created by PhpStorm.
 * User: yuyj
 * Date: 16-12-9
 * Time: 下午5:20
 */

namespace common\services\outstock;

use common\entities\myhtsq\ContractManageEntity;
use common\entities\outstock\MyscrmOutStockStepEntity;
use common\entities\outstock\MyscrmOutStockOrderEntity;
use common\models\common\ErpUserModel;
use common\models\common\OperatorModel;
use common\repositories\outstock\OutStockFlowRepository;
use common\services\BaseService;
use common\services\common\MyscrmContractManageService;
use common\services\common\MyscrmContractService;
use common\services\common\MyscrmOrganizationService;
use common\services\myhtsq\ErpUserService;
use common\support\EmailHelper;
use Yii;
use yii\base\Exception;

/**
 * 出库流程
 * 动作：发起，审批，确认，开通，打回，撤回
 * 状态：申请中，已审批，已确认，已开通，未发起
 *
 * Class OutStockFlowService
 * @package common\services\outstock
 * @property  MyscrmOutStockOrderEntity $order    单据模型
 * @property  OperatorModel $operator 操作者模型
 */
class OutStockFlowService extends BaseService
{
    const STATUS_DEFAULT = '未发起';

    const STATUS_WFQ = 0;//未发起
    const STATUS_SQZ = 10;//申请中
    const STATUS_YSP = 20;//已审批
    const STATUS_YQR = 21;//已确认
    const STATUS_YKT = 30;//已开通
    const STATUS_YSQ = 31;//已授权

    const ACTION_FQ = 1;///发起
    const ACTION_DH = 10;//打回
    const ACTION_CH = 11;//撤回
    const ACTION_SP = 20;//审批
    const ACTION_QR = 21;//确认
    const ACTION_KT = 22;//开通
    const ACTION_SQ = 23;//授权

    public static $statusMap = [
        self::STATUS_WFQ => '未发起',
        self::STATUS_SQZ => '申请中',
        self::STATUS_YSP => '已审批',
        self::STATUS_YQR => '已确认',
        self::STATUS_YKT => '已开通',
        self::STATUS_YSQ => '已授权',
    ];

    public static $actionMap = [
        self::ACTION_FQ => '发起',
        self::ACTION_DH => '打回',
        self::ACTION_CH => '撤回',
        self::ACTION_SP => '审批',
        self::ACTION_QR => '确认',
        self::ACTION_KT => '开通',
        self::ACTION_SQ => '授权',
    ];

    //单据状态对应步骤说明
    public static $currentStepMap = [
        self::STATUS_WFQ => '草稿',
        self::STATUS_SQZ => '上级审批',
        self::STATUS_YSP => '财务复核',
        self::STATUS_YQR => '已确认',
        self::STATUS_YKT => '已开通租户',
        self::STATUS_YSQ => '已开通授权',
    ];

    //单据状态对应审批人
    public static $approverMap = [
        self::STATUS_WFQ => '发起人',
        self::STATUS_SQZ => '区域负责人',
        self::STATUS_YSP => '财务负责人',
        self::STATUS_YQR => '财务负责人',
        self::STATUS_YKT => '财务负责人',
        self::STATUS_YSQ => '财务负责人',
    ];

    public $order;// 单据模型
    public $operator;// 操作者模型

    private $next_status; // 当前状态
    private $special_permit = false; // 是否特批
    private $special_permit_type; // 特批类型
    private $action; //当前动作
    private $remarks; // 备注
    private $flow_step_id; //当前流程步骤ID

    /**
     * @inheritdoc
     */
    public function __construct(OutStockFlowRepository $repository, $config = [])
    {
        return parent::__construct($config);
    }

    public function init()
    {
        if (!$this->order || !($this->order instanceof MyscrmOutStockOrderEntity) || !$this->order->id) {
            throw new Exception('缺少 order 参数，或者参数order不是 MyscrmOutStockOrderEntity 的实例。');
        }

        if (!$this->operator || !($this->operator instanceof OperatorModel)) {
            throw new Exception('缺少operator参数，或者参数 operator 不是 OperatorModel 的实例。');
        }
    }

    /**
     * 获取单据是否为特批
     * @return bool
     */
    public function getSpecialPermit()
    {
        return $this->special_permit = !($this->order->contract_status && $this->order->money_status);
    }

    /**
     * 获取单据的特批类型
     * @return int
     */
    public function getSpecialPermitType()
    {
        if ($this->order->contract_status && $this->order->money_status) {
            $this->special_permit_type = 0;
        }

        if ($this->order->contract_status && !$this->order->money_status) {
            $this->special_permit = 0;
        }

        if (!$this->order->contract_status && $this->order->money_status) {
            $this->special_permit = 0;
        }

        if (!$this->order->contract_status && !$this->order->money_status) {
            $this->special_permit = 0;
        }

        return $this->special_permit;
    }

    /**
     * 发起
     * @param $responseUserId
     * @return bool
     */
    public function actionFQ($responseUserId)
    {
        $this->action = self::ACTION_FQ;

        //非未申请状态，不允许发起
        if ($this->checkActionCondition($this->order->flow_status != self::STATUS_WFQ) === false) {
            return false;
        }


        $this->next_status = self::STATUS_SQZ;

        $this->order->response_user_id = $responseUserId;


        if ($this->doAction() === false) {
            return false;
        } else {
            $this->noticeFQ();

            return true;
        }
    }

    /**
     * 审批
     * 审核后需要调整单据责任人，经由财务确认
     * @return bool
     */
    public function actionSP()
    {
        $this->action = self::ACTION_SP;

        //不是特批，非申请中，不允许审批
        if ($this->checkActionCondition(!$this->getSpecialPermit() && $this->order->flow_status != self::STATUS_SQZ) === false) {
            return false;
        }

        $this->next_status = self::STATUS_YSP;

        $transaction = MyscrmOutStockStepEntity::getDb()->beginTransaction();
        try {

            if ($this->createFlowStep() && $this->changeResponserToFinance() && $this->saveOrderStatus()) {
                $transaction->commit();

                $this->noticeSP();

                return true;
            } else {
                return false;
            }

        } catch (Exception $e) {
            $transaction->rollBack();

            return self::setAndReturn($e->getCode(), $e->getMessage());
        }
    }

    /**
     * 确认
     * @return bool
     */
    public function actionQR()
    {
        $this->action = self::ACTION_QR;

        //特批，非已审批状态，不允许确认
        if ($this->checkActionCondition($this->getSpecialPermit() && ($this->order->flow_status != self::STATUS_YSP)) === false) {
            return false;
        }

        //不是特批，非申请中状态，不允许确认
        if ($this->checkActionCondition(!$this->getSpecialPermit() && $this->order->flow_status != self::STATUS_SQZ) === false) {
            return false;
        }

        $this->next_status = self::STATUS_YQR;

        if ($this->doAction() === false) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 开通
     * @param $org_name
     * @param $org_id
     * @param $org_code
     * @param $password
     * @return bool
     */
    public function actionKT($org_name, $org_id, $org_code, $password)
    {
        $this->action = self::ACTION_KT;

        if ($this->order->org_code) {
            return self::setAndReturn(__LINE__, '只有新租户才允许开通。');
        }

        //非已确认状态，不允许开通
        if ($this->checkActionCondition($this->order->flow_status != self::STATUS_YQR) === false) {
            return false;
        }

        $this->next_status = self::STATUS_YKT;

        //回填租户ID
        $this->order->org_id = $org_id;
        $this->order->org_code = $org_code;

        if ($this->doAction() === false) {
            return false;
        } else {
            $this->noticeKT($org_name, $org_code, $password);

            return true;
        }
    }

    /**
     * 授权
     * @param $beginOn
     * @param $endOn
     * @return bool
     */
    public function actionSQ($beginOn, $endOn)
    {
        $this->action = self::ACTION_SQ;

        //新租户，非已开通状态，不允许授权
        if ($this->checkActionCondition($this->order->is_new_org && $this->order->flow_status != self::STATUS_YKT) === false) {
            return false;
        }

        //老租户，非已确认状态，不允许授权
        if ($this->checkActionCondition(!$this->order->is_new_org && $this->order->flow_status != self::STATUS_YQR) === false) {
            return false;
        }
        $this->next_status = self::STATUS_YSQ;

        if ($this->doAction() === false) {
            return false;
        } else {
            $this->noticeSQ($beginOn, $endOn);

            return true;
        }
    }

    /**
     * 打回
     * 打回后，需要调整单据责任人，责任人需要回退
     * @param $remarks
     * @return bool
     */
    public function actionDH($remarks)
    {
        $this->action = self::ACTION_DH;

        //未发起状态，已确认状态，已开通，已授权 不允许打回
        if ($this->checkActionCondition(in_array($this->order->flow_status, [
                self::STATUS_WFQ,
                self::STATUS_YQR,
                self::STATUS_YKT,
                self::STATUS_YSQ,
            ])) === false
        ) {
            return false;
        }

        $this->remarks = $remarks;
        $this->next_status = self::STATUS_WFQ;

        $transaction = MyscrmOutStockStepEntity::getDb()->beginTransaction();
        try {

            if ($this->createFlowStep() && $this->autoChangeResponser() && $this->saveOrderStatus()) {
                $transaction->commit();

                $this->noticeDH();

                return true;
            } else {
                return false;
            }

        } catch (Exception $e) {
            $transaction->rollBack();

            return self::setAndReturn($e->getCode(), $e->getMessage());
        }
    }

    /**
     * 撤回
     * @param $remarks
     * @return bool
     */
    public function actionCH($remarks)
    {
        $this->action = self::ACTION_CH;

        //非申请中的状态，不允许撤回
        if ($this->checkActionCondition($this->order->flow_status != self::STATUS_SQZ) === false) {
            return false;
        }

        if ($this->order->request_user_id != $this->operator->user_id && $this->order->deliver_user_id != $this->operator->user_id) {
            return self::setAndReturn(__LINE__, '只能撤回自己发起的单据');
        }

        $this->remarks = $remarks;
        $this->next_status = self::STATUS_WFQ;

        if ($this->doAction() === false) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 检查动作执行的条件
     * @param $condition
     * @return bool
     */
    private function checkActionCondition($condition)
    {
        //已授权，直接返回
        if($this->order->flow_status == self::STATUS_YSQ){
            return true;
        }

        //已开通，直接返回
        if($this->order->flow_status == self::STATUS_YKT){
            return true;
        }

        if ($condition) {
            if (!isset(self::$actionMap[$this->action])) {
                return self::setAndReturn(__LINE__, sprintf('当前动作 %s 未定义', $this->action));
            }

            if (!isset(self::$statusMap[$this->order->flow_status])) {
                return self::setAndReturn(__LINE__, sprintf('当前状态 %s 未定义', $this->order->flow_status));
            }

            return self::setAndReturn(__LINE__, sprintf('当前状态 %s 不允许 %s', self::$statusMap[$this->order->flow_status], self::$actionMap[$this->action]));
        }

        return true;
    }

    /**
     * 保存订单状态
     * @return bool
     */
    private function saveOrderStatus()
    {
        $this->order->flow_step_id = $this->flow_step_id;
        $this->order->flow_status = $this->next_status;

        if ($this->order->save() === false) {
            $errors = $this->order->getFirstErrors();

            return self::setAndReturn(__LINE__, implode(';', $errors));
        }

        return true;
    }

    /**
     * 创建流程步骤
     * @return bool|string
     */
    private function createFlowStep()
    {
        /** @var OutStockStepService $service */
        $service = Yii::createObject(OutStockStepService::className());

        $model = new MyscrmOutStockStepEntity();
        $model->order_id = $this->order->id;
        $model->operate_people_id = $this->operator->user_id;
        $model->operate_people_department_id = $this->operator->department_id;
        $model->action = $this->action;
        $model->remarks = $this->remarks;

        $this->flow_step_id = $service->create($model);

        return $this->flow_step_id;
    }

    /**
     * @return bool
     */
    private function doAction()
    {
        $transaction = MyscrmOutStockStepEntity::getDb()->beginTransaction();
        try {

            if ($this->createFlowStep() && $this->saveOrderStatus()) {
                $transaction->commit();

                return true;
            } else {
                return false;
            }

        } catch (Exception $e) {
            $transaction->rollBack();

            return self::setAndReturn($e->getCode(), $e->getMessage());
        }
    }

    /**
     * 将当前负责人切换为财务
     */
    private function changeResponserToFinance()
    {
        /** @var ErpUserService $service */
        $service = Yii::createObject(ErpUserService::className());
        $data = $service->getFinanceChargeList();

        if (empty($data)) {
            return self::setAndReturn(__LINE__, '未定义财务负责人');
        }

        $this->order->response_user_id = $data[0]['UserGUID'];

        return true;
    }

    /**
     * 自动切换单据责任人
     * @return bool
     */
    private function autoChangeResponser()
    {

//        if ($this->special_permit) {
//            /** @var OutStockStepService $service */
//            $service = Yii::createObject(OutStockStepService::className());
//            $data = $service->getLatestSpUser($this->order->id);
//
//            if (empty($data)) {
//                return self::setAndReturn(__LINE__, '找不到最后的审批者');
//            }
//
//            $this->order->response_user_id = $data['UserGUID'];
//        } else {
//
//        }

        //清空责任人
        $this->order->response_user_id = null;

        return true;
    }

    /**
     * 获取 LDAP 用户信息
     * @param $userId
     * @return ErpUserModel|boolean
     */
    private function getUserById($userId)
    {
        /** @var ErpUserService $service */
        $service = Yii::createObject(ErpUserService::className());
        $user = $service->getUserById($userId);

        if (empty($user)) {
            return self::setAndReturn(__LINE__, '用户 ' . $userId . ' 不存在');
        }

        if (empty($user['Email'])) {
            return self::setAndReturn(__LINE__, '用户的邮件未设置。');
        }

        //test
        //$user['Email'] = 'yuyj@mingyuanyun.com';

        return $user;
    }

    /**
     * 审批通知
     * @return bool
     */
    private function noticeSP()
    {
        //给发起人邮件通知
        $requestUser = $this->getUserById($this->order->request_user_id);

        if (empty($requestUser)) {
            return false;
        }

        $subject = sprintf('申请开通云客授权—%s，已审批通过', $this->order->customer_name);
        $template = <<<EOF
你好，你发起的出库申请，已审批通过！<br />
【审批时间】：%s<br />
【审批结果】：同意<br />
【审 批 人】：%s<br />
<br />
要立即查看，单击 %s 进入系统！<br />
EOF;
        $html = sprintf($template,
            date('Y-m-d H:i:s'),
            $this->operator->username,
            $this->getOrderLink('start')
        );

        $this->emailTo($requestUser['Email'], $subject, $html);

        $fqStep = $this->getLatestFqStep($this->order->id);

        if ($fqStep === false) {
            return self::setAndReturn(__LINE__, '未找到发起流程 orderId:' . $this->order->id);
        }

        //给财务人员发邮件通知
        $responseUser = $this->getUserById($this->order->response_user_id);

        if (empty($responseUser)) {
            return false;
        }

        $subject = sprintf('申请开通云客授权—%s', $this->order->customer_name);
        $template = <<<EOF
你好，申请开通%s云客授权。<br />
【申 请 人】：%s<br />
【申请时间】：%s<br />
<br />
【审批时间】：%s<br />
【审批结果】：同意<br />
【审 批 人】：%s<br />
<br />
要立即查看，单击 %s 进入系统！
EOF;
        $html = sprintf($template,
            $this->order->customer_name,
            $requestUser['UserName'],
            $fqStep->created_on,
            date('Y-m-d H:i:s'),
            $this->operator->username,
            $this->getOrderLink('todo')
        );

        return $this->emailTo($responseUser['Email'], $subject, $html);
    }

    /**
     * 打回通知
     */
    private function noticeDH()
    {
        $user = $this->getUserById($this->order->request_user_id);

        if (empty($user)) {
            return false;
        }

        $subject = sprintf('申请开通云客授权—%s，被打回', $this->order->customer_name);
        $template = <<<EOF
你好，你发起的出库申请，被打回！<br />
<br />
【审批时间】：%s<br />
【审批结果】：不同意，%s<br />
【审 批 人】：%s<br />
<br />
要立即查看，单击 %s 进入系统！
EOF;
        $html = sprintf($template,
            date('Y-m-d H:i:s'),
            $this->remarks,
            $this->operator->username,
            $this->getOrderLink('start')
        );

        return $this->emailTo($user['Email'], $subject, $html);
    }

    /**
     * 发起通知
     */
    private function noticeFQ()
    {
        $user = $this->getUserById($this->order->response_user_id);

        if (empty($user)) {
            return false;
        }

        $subject = sprintf('申请开通云客授权—%s', $this->order->customer_name);
        $template = <<<EOF
你好，申请开通%s云客授权。<br />
【申 请 人】：%s<br />
【申请时间】：%s<br />
<br />
要立即查看，单击 %s 进入系统！<br />
EOF;
        $html = sprintf($template,
            $this->order->customer_name,
            $this->operator->username,
            date('Y-m-d H:i:s'),
            $this->getOrderLink('todo')
        );

        return $this->emailTo($user['Email'], $subject, $html);
    }

    /**
     * 开通通知
     * @param $org_name
     * @param $org_code
     * @param $password
     * @return bool
     */
    private function noticeKT($org_name, $org_code, $password)
    {
        $user = $this->getUserById($this->order->request_user_id);

        if (empty($user)) {
            return false;
        }

        $subject = sprintf('申请开通云客授权—%s，已开通租户', $this->order->customer_name);
        $template = <<<EOF
【租  户】：%s<br />
【企业号】：%s<br />
【密  码】：%s<br />
EOF;
        $html = sprintf($template,
            $org_name, $org_code, $password
        );

        return $this->emailTo($user['Email'], $subject, $html);
    }

    /**
     * 通过合同查询区域
     * @param $contractCode
     * @return bool|string
     * @throws \yii\base\InvalidConfigException
     */
    private function _getAreaNameContractCode($contractCode)
    {
        if (empty($contractCode)) {
            return self::setAndReturn(__LINE__, '合同编号不能为空');
        }
        /** @var MyscrmContractManageService $service */
        $service = Yii::createObject(MyscrmContractManageService::className());
        $contractManage = $service->getContractManageByCode($contractCode);
        if (!$contractManage->area_id) {
            return self::setAndReturn(__LINE__, '合同对应区域为空');
        }
        return $service->getBunameByBuguid($contractManage->area_id);
    }

    /**
     * 查询租户名
     * @param $orgId
     * @return bool|mixed
     * @throws \yii\base\InvalidConfigException
     */
    private function _getOrgNameByOrgId($orgId)
    {
        /** @var MyscrmOrganizationService $service */
        $service = Yii::createObject(MyscrmOrganizationService::className());
        $org = $service->getOrgById($orgId);
        if (!empty($org)) {
            return $org->FriendlyName;
        } else {
            return self::setAndReturn(__LINE__, '没有此租户，orgid:' . $orgId);
        }
    }

    /**
     * 授权通知
     * @param $beginOn
     * @param $endOn
     * @return bool
     */
    private function noticeSQ($beginOn, $endOn)
    {
        $user = $this->getUserById($this->order->request_user_id);

        if (empty($user)) {
            return false;
        }

        $products = $this->getProducts($this->order->id);
        if (empty($products)) {
            return self::setAndReturn(__LINE__, '未找到单据的授权信息');
        }


        $html = '';
        if ($this->order->contract_id) {

            $contract = $this->getContract($this->order->contract_code);
            if (empty($contract)) {
                return self::setAndReturn(__LINE__, '找不到对应的合同信息 contract code:'.$this->order->contract_code);
            }
            $area_name = $this->_getAreaNameContractCode($this->order->contract_code);
            $orgName = $this->_getOrgNameByOrgId($this->order->org_id);
            $template = <<<EOF
        <br />
        <br />
【区    域】：%s<br />
【租    户】：%s<br />
【企 业 号】：%s<br />
【合 同 号】：%s<br />
【合同甲方】：%s<br />
【租    期】：%s到%s<br />
EOF;
            $html .= sprintf($template,
                $area_name,
                $orgName,
                $this->order->org_code,
                $this->order->contract_code,
                $contract->customer_full_name,
                substr($beginOn, 0, 10),
                substr($endOn, 0, 10)
            );
        } else {
            $orgName = $this->_getOrgNameByOrgId($this->order->org_id);
            $template = <<<EOF
        <br />
        <br />
【租    户】：%s<br />
【企 业 号】：%s<br />
EOF;
            $html .= sprintf($template,
                $orgName,
                $this->order->org_code
            );
        }

        $info = [];

        foreach ($products as $product) {
              //未申请授权的应用，不需要展示在邮件中。
            if ($product['apply_num'] <= 0) {
                continue;
            }

            $bind_project = [];
            if ($product['bind_project']) {
                foreach ($product['bind_project'] as $p) {
                    $bind_project[] = $p['proj_name'];
                }
            }

            if ($bind_project) {
                $info[] = sprintf('• %s：%d个授权（%s）', $product['application_name'], $product['apply_num'], implode('，', $bind_project));
            } else {
                $info[] = sprintf('• %s：%d个授权', $product['application_name'], $product['apply_num']);
            }
        }

        $subject = sprintf('申请开通云客授权—%s，已开通授权', $this->order->customer_name);
        $template = <<<EOF
        <br />
        <br />
授权信息如下：<br />
%s<br />
<br />
要立即查看，单击 %s 进入系统！<br />
EOF;
        $html .= sprintf($template,
            implode("<br />", $info),
            $this->getOrderLink('start')
        );

        return $this->emailTo($user['Email'], $subject, $html);
    }

    /**
     * 获取最后一个发起流水
     * @param $orderId
     * @return MyscrmOutStockStepEntity
     */
    private function getLatestFqStep($orderId)
    {
        /** @var OutStockStepService $service */
        $service = Yii::createObject(OutStockStepService::className());

        return $service->getLatestFqStep($orderId);
    }

    /**
     * 获取单据链接
     * @param string $type start:我发起的 to.do:我的待办 done:我的已办
     * @return string
     */
    private function getOrderLink($type = 'start')
    {
        return sprintf(
            '<a href="http://rent.myscrm.cn/index.shtml#/process_center?type=%s&id=%s">%s</a>',
            $type,
            $this->order->id,
            $this->order->order_code
        );
    }

    /**
     * 获取授权产品
     * @param $orderId
     * @return \common\entities\outstock\MyscrmOutStockProductEntity[]
     */
    private function getProducts($orderId)
    {
        /** @var OutStockProductService $service */
        $service = Yii::createObject(OutStockProductService::className());

        return $service->getProductsByOrderId($orderId);
    }

    /**
     * 获取单据关联合同
     * @param $contractCode
     * @return ContractManageEntity
     */
    private function getContract($contractCode)
    {
        /** @var MyscrmContractManageService $service */
        $service = Yii::createObject(MyscrmContractManageService::className());

        return $service->getContractManageByCode($contractCode);
    }

    private function emailTo($to, $subject, $body)
    {
        Yii::$app->mailer->messageConfig['from'] = ['yunkeadmin@mysoft.com.cn' => 'hetong-yunke@mingyuanyun.com'];

        return EmailHelper::send($to, $subject, $body);
    }
}